package com.spring.beanpostprocessor;

import com.spring.context.impl.AbstractApplicationContext;
import com.spring.event.ApplicationEvent;
import com.spring.event.EventListener;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author ljj
 */
public class EventPostProcessor implements BeanPostProcessor {
	
	private final AbstractApplicationContext ac;
	
	public EventPostProcessor(AbstractApplicationContext ac) {
		this.ac = ac;
	}
	
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		if (bean instanceof EventListener) {
			Class<? extends ApplicationEvent> eventClass = findEventClass(bean.getClass());
			if (eventClass != null) {
				ac.addListener(eventClass, (EventListener<?>) bean);
			}
		}
		return bean;
	}
	
	@SuppressWarnings("unchecked")
	private Class<? extends ApplicationEvent> findEventClass(Class<?> clazz) {
		while (clazz != null && clazz != Object.class) {
			Type[] interfaces = clazz.getGenericInterfaces();
			if (interfaces.length == 0) {
				clazz = clazz.getSuperclass();
			} else {
				for (Type type : interfaces) {
					if (type instanceof ParameterizedType) {
						ParameterizedType pt = (ParameterizedType) type;
						if (pt.getRawType() == EventListener.class) {
							Type actualTypeArgument = pt.getActualTypeArguments()[0];
							return (Class<? extends ApplicationEvent>) actualTypeArgument;
						}
					} else if (type instanceof Class) {
						Class<?> tempClazz = (Class<?>) type;
						if (EventListener.class.isAssignableFrom(tempClazz)) {
							Class<? extends ApplicationEvent> ret = findEventClass(tempClazz);
							if (ret != null) {
								return ret;
							}
						}
					}
				}
			}
		}
		return null;
	}
	
	
	public static class A implements EventListener<ApplicationEvent>{
		
		@Override
		public void onMessage(ApplicationEvent event) {
		
		}
	}
	
	public static class MyApplicationEvent extends ApplicationEvent {
	
	}
	
	public static class B implements EventListener<MyApplicationEvent>{
		
		@Override
		public void onMessage(MyApplicationEvent event) {
		
		}
	}
	
	public static void main(String[] args) {
		
		A a = new A();
		B b = new B();
		addListener(MyApplicationEvent.class, a);
		addListener(MyApplicationEvent.class, b);
		
	}
	
	public static void addListener(Class<? extends ApplicationEvent> event, EventListener<? extends ApplicationEvent> listener) {
	}
}
